package com.handpay.framework.swiper;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.text.TextUtils;

import com.handpay.framework.ClientEngine;
import com.handpay.framework.utils.CommonUtils;
import com.handpay.zztong.hp.R;
import com.handpay.zztong.hp.other.activity.ShowHtmlActivity;
import com.handpay.zztong.hp.config.UPConfig;
import com.handpay.zztong.hp.config.ZZTConfig;
import com.handpay.zztong.hp.log.HPLog;
import com.newland.me.ConnUtils;
import com.newland.me.DeviceManager;
import com.newland.mtype.ConnectionCloseEvent;
import com.newland.mtype.Device;
import com.newland.mtype.DeviceInfo;
import com.newland.mtype.DeviceOutofLineException;
import com.newland.mtype.DeviceRTException;
import com.newland.mtype.ModuleType;
import com.newland.mtype.ProcessTimeoutException;
import com.newland.mtype.common.ExCode;
import com.newland.mtype.common.MESeriesConst;
import com.newland.mtype.common.MESeriesConst.TrackEncryptAlgorithm;
import com.newland.mtype.conn.DeviceConnParams;
import com.newland.mtype.event.AbstractProcessDeviceEvent;
import com.newland.mtype.event.DeviceEvent;
import com.newland.mtype.event.DeviceEventListener;
import com.newland.mtype.module.common.cardreader.CardReader;
import com.newland.mtype.module.common.cardreader.OpenCardReaderEvent;
import com.newland.mtype.module.common.emv.EmvControllerListener;
import com.newland.mtype.module.common.emv.EmvModule;
import com.newland.mtype.module.common.emv.EmvTransController;
import com.newland.mtype.module.common.emv.EmvTransInfo;
import com.newland.mtype.module.common.emv.QPBOCModule;
import com.newland.mtype.module.common.lcd.LCD;
import com.newland.mtype.module.common.pin.AccountInputType;
import com.newland.mtype.module.common.pin.EncryptType;
import com.newland.mtype.module.common.pin.MacAlgorithm;
import com.newland.mtype.module.common.pin.PinInput;
import com.newland.mtype.module.common.pin.PinInputEvent;
import com.newland.mtype.module.common.pin.PinManageType;
import com.newland.mtype.module.common.pin.WorkingKey;
import com.newland.mtype.module.common.swiper.SwipResult;
import com.newland.mtype.module.common.swiper.SwipResultType;
import com.newland.mtype.module.common.swiper.Swiper;
import com.newland.mtype.module.common.swiper.SwiperReadModel;
import com.newland.mtype.module.common.swiper.TrackSecurityPaddingType;
import com.newland.mtype.util.ISOUtils;
import com.newland.mtypex.bluetooth.BlueToothV100ConnParams;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 新大陆刷卡器的封装
 * 
 * @author jmshuai
 * 
 */
class NewlandSwiperBT implements IBusinessSwiper {
	private static final String TAG = "NewlandSwiperBT";
	private static final String BANK_ACCOUNT_HASH_KEY = "account_hash";
	protected DeviceManager mDeviceManager;
	private static final String ME3X_DRIVER_NAME = "com.newland.me.ME3xDriver";
	private volatile boolean mIsSwiperOK = true;
	private DeviceConnParams mConnParams;
	private Hashtable<String, String> mHTData = new Hashtable<String, String>();
	// 用于获取字符串
	private Context mContext;

	/**
	 * 初始化设备
	 * 
	 * @param context
	 * @param params
	 */
	private void initMe3xDeviceController(Context context, DeviceConnParams params) {
		mConnParams = params;
		mContext = context;
		mDeviceManager.init(context, ME3X_DRIVER_NAME, params, new DeviceEventListener<ConnectionCloseEvent>() {
			@Override
			public void onEvent(ConnectionCloseEvent event, Handler handler) {
				if (event.isSuccess()) {
					// appendInteractiveInfoAndShow("设备被客户主动断开！");
					HPLog.e(TAG, "〈〈〈〈〈DeviceEventListener〉〉〉〉〉Exception--event.isSuccess()");
					mIsSwiperOK = false;
				}
				if (event.isFailed()) {
					// appendInteractiveInfoAndShow("设备链接异常断开！" +
					// event.getException().getMessage());
					HPLog.e(TAG, "〈〈〈〈〈DeviceEventListener〉〉〉〉〉Exception--event.isFailed()");
					mIsSwiperOK = false;
				}
			}

			@Override
			public Handler getUIHandler() {
				return null;
			}
		});
		// appendInteractiveInfoAndShow("驱动版本号："+controller.getCurrentDriverVersion());
	}

	/**
	 * 尝试连接刷卡器。请在每个刷卡器操作之前执行此操作。
	 * 
	 * @return true表示连接成功，否则连接失败
	 */
	public boolean connect() {
		try {
			// 刷卡器连接前做延时操作,避免极个别手机在设备不存在蓝牙配对列表中时出错。
			Thread.sleep(300);

			mDeviceManager.connect();
			mDeviceManager.getDevice().setBundle(mConnParams);
		} catch (Exception e) {
			HPLog.i(TAG, "", e);
			HPLog.e(TAG, "〈〈〈〈〈connect〉〉〉〉〉Exception");
			mIsSwiperOK = false;
		}
		return mIsSwiperOK;
	}

	/**
	 * 加密之前，先格式化数据。
	 * 
	 * @param data
	 * @param cover
	 * @return
	 */
	public static byte[] formatEncData(byte[] data, int cover) {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			bos.write(data);
		} catch (IOException e) {
			return null;
		}
		if (bos.size() % 8 != 0) {
			bos.write(0x00);
			while (bos.size() % 8 != 0) {
				bos.write(cover);
			}
		}
		return bos.toByteArray();
	}

	private String encData(String data, String factor) {
		String str = null;
		if (!connect()) {
			return str;
		}
		try {
			HPLog.i(TAG, "encData: before:" + data);
			WorkingKey localWorkingKey = new WorkingKey(MKIndexConst.DEFAULT_MUTUALAUTH_WK_INDEX, CommonUtils.hexStringToBytes(factor));
			byte[] array = formatEncData(CommonUtils.hexStringToBytes(data), 0x00);
			HPLog.i(TAG, "encData: before:" + CommonUtils.bytesToHexString(array));
			PinInput pinInput = (PinInput) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_PININPUT);
			str = CommonUtils.bytesToHexString(pinInput.encrypt(localWorkingKey, EncryptType.DISPERSE_ECB, array, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }));
			HPLog.i(TAG, "encData: after:" + str);
			return str.toUpperCase(Locale.US);
		} catch (Exception localException) {
			HPLog.e(TAG, "encData", localException);
		}
		return str;
	}

	private String encMac(byte[] data, String factor) {
		String str = null;
		if (!connect()) {
			return str;
		}
		try {
			PinInput pinInput = (PinInput) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_PININPUT);
			byte[] arrayOfByte = pinInput.calcMac(MacAlgorithm.DISPERSE_MAC_X99, PinManageType.FIXED, new WorkingKey(MKIndexConst.DEFAULT_MAC_WK_INDEX, CommonUtils.hexStringToBytes(factor)), data);
			byte[] retBuf = new byte[4];
			System.arraycopy(arrayOfByte, 0, retBuf, 0, 4);
			str = CommonUtils.bytesToHexString(retBuf);
			return str.toUpperCase(Locale.US);
		} catch (Exception e) {
			HPLog.e(TAG, "calc mac failed", e);
		}
		return str;
	}

	public NewlandSwiperBT(Context context, String address) {
		mDeviceManager = ConnUtils.getDeviceManager();
		try {
			initMe3xDeviceController(context, new BlueToothV100ConnParams(address));
		} catch (Exception e) {
			HPLog.i(TAG, "", e);
			mIsSwiperOK = false;
		}
	}

	@Override
	public String getCSN() {
		if (connect()) {
			try {
				DeviceInfo deviceInfo = mDeviceManager.getDevice().getDeviceInfo();
				HPLog.i("getCSN", deviceInfo);
				String csn = deviceInfo.getCSN();
				if (null != deviceInfo && !ZZTConfig.ENV.SWIPERCSN) {
					csn = ZZTConfig.ENV.CSN;
				}
				if (!TextUtils.isEmpty(csn)) {
					csn = csn.replace("=", "D");
				}
				HPLog.e("CSN", csn);
				return csn;
			} catch (ProcessTimeoutException processTimeoutException) {
				HPLog.e(TAG, "", processTimeoutException);
			} catch (Exception e) {
				HPLog.e(TAG, "", e);
			}
		}
		return null;
	}

	@Override
	public boolean stopOperation() {
		boolean result = false;
		if (DeviceManager.DeviceConnState.CONNECTED == mDeviceManager.getDeviceConnState()) {
			try {
				mDeviceManager.getDevice().reset();
				result = true;
			} catch (Exception e) {
				HPLog.e(TAG, "撤消指令执行失败!", e);
			}
		}
		return result;
	}

	@Override
	public boolean closeDevice() {
		mContext = null;
		mConnParams = null;
		mIsSwiperOK = false;
		if (mDeviceManager != null) {
			mDeviceManager.destroy();
			mDeviceManager = null;
		}
		return true;
	}

	private void clearScreen() {
		if (mDeviceManager == null) {
			return;
		}
		// 避免程序崩溃
		Device d = mDeviceManager.getDevice();
		if (null == d) {
			return;
		}
		LCD lcd = (LCD) d.getStandardModule(ModuleType.COMMON_LCD);
		if (lcd != null) {
			lcd.clearScreen();
		}
	}

	private String mDynamicKey;

	@Override
	public SwipeResult swipeCard(String factor, int timeout) {
		// HPLog.i(TAG, "2014070707070780 : 0123456789abcdef");
		// String encMac =
		// encData("0123456789abcdef",ISwiperListener.MacDataIndex ,
		// "2014070707070780");
		// HPLog.i(TAG, "mac: " + encMac);
		SwipeResult swipeResult;
		mDynamicKey = CommonUtils.bytesToHexString(getDynamicKeyData());
		mHTData.clear();
		try {
			// String message;
			String swipe = mContext.getString(R.string.newland_swipe);
			// 如果，用户确认过金额，显示金额。没有直接显示请刷卡
			// 如果超级转账，金额也不是显示的。
			if (TextUtils.isEmpty(mAmount) || mFlag == SwiperMode.SUPER_TRANS) {
				message = swipe;
			} else {
				BigDecimal bd = new BigDecimal(mAmount);
				bd = bd.divide(new BigDecimal("100"));
				// message = mContext.getString(R.string.newland_amount)
				// + bd.toString() + "\n" + swipe;
				message = swipe;
			}
			clearScreen();
			// SwipResult result = swipCard(message, timeout, factor,
			// CommonUtils.hexStringToBytes(mDynamicKey));
			// Caojun 刷卡
			SwipResult result = null;
			try {
				BigDecimal amt = null;
				if (!TextUtils.isEmpty(mAmount)) {
					amt = new BigDecimal(mAmount);
				}
				icTransferListener.setFactor(factor);
				result = startTransfer(new ModuleType[] { ModuleType.COMMON_SWIPER, ModuleType.COMMON_ICCARD, ModuleType.COMMON_NCCARD }, message, amt, factor, CommonUtils.hexStringToBytes(mDynamicKey), timeout, TimeUnit.SECONDS, icTransferListener);
			} catch (DeviceRTException e) {
				if (e.code == Integer.MIN_VALUE) {
					if ("IC".equals(e.getMessage())) {
						// IC卡
						HPLog.e("icSwipeResult", "icSwipeResult");
						if (null == icSwipeResult) {
							return new SwipeResult(SwipeStatus.SWIPE_ERROR);
						} else {
							mHTData.put(BANK_DYNAMIC_KEY, mDynamicKey.toUpperCase(Locale.US));
							return icSwipeResult;
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				return new SwipeResult(SwipeStatus.SWIPE_ERROR);
			} finally {
				clearScreen();
			}
			if (null == result) {
				return new SwipeResult(SwipeStatus.SWIPE_CANCEL);
			}
			// readTrack_timeout当做读卡超时
			if (SwipResultType.READTRACK_TIMEOUT == result.getRsltType()) {
				return new SwipeResult(SwipeStatus.SWIPE_TIMEOUT);
			}
			if (null == result.getSecondTrackData()) {
				return new SwipeResult(SwipeStatus.SWIPE_ERROR);
			}
			// 刷卡的时候，记录二磁道，dynamicKey, 还有卡号明文.
			// 其他的，譬如pin,卡号密文，金额密文等。输入密码后，做加密后加入。
			mHTData.put(BANK_TRACK2_KEY, CommonUtils.bytesToHexString(result.getSecondTrackData()).toUpperCase(Locale.US));
			mHTData.put(BANK_DYNAMIC_KEY, mDynamicKey.toUpperCase(Locale.US));
			mHTData.put(BANK_PLAIN_ACCOUNT_KEY, result.getAccount().getAcctNo());
			// 保存hashKey，用于输入密码用
			mHTData.put(BANK_ACCOUNT_HASH_KEY, result.getAccount().getAcctHashId());
			// 新版2.0.0 expiryDate
			String expireDate = result.getValidDate();
			if (CommonUtils.checkExpireDate(expireDate)) {
				expireDate = expireDate.substring(0, 4);
				HPLog.i(HPLog.FDL_TAG, "GjackSwiper  -- plainExpireDate:" + expireDate);
				mHTData.put(IBusinessSwiper.BANK_PLAIN_EXPIRE_DATE, expireDate);
			} else {
				HPLog.i(TAG, "GjackSwiper IC card but no plainExpireDate");
			}

			swipeResult = new SwipeResult(SwipeStatus.SWIPE_OK, result.getAccount().getAcctNo());
			swipeResult.mCardType = result.getServiceCode().substring(0, 1);

		} catch (ProcessTimeoutException processTimeoutException) {
			HPLog.e(TAG, "", processTimeoutException);
			swipeResult = new SwipeResult(SwipeStatus.SWIPE_TIMEOUT);
		} catch (DeviceRTException e) {
			HPLog.e(TAG, "", e);
			swipeResult = new SwipeResult(SwipeStatus.SWIPE_ERROR);
		}
		return swipeResult;
	}

	private SwipResult swipCard(String msg, long timeout, String factor, byte[] dynamicData) {
		CardReader cardReader = (CardReader) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_CARDREADER);
		if (cardReader == null) {
			throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED, "not support read card!");
		}
		try {
			ModuleType[] openedModuleTypes = cardReader.openCardReader(msg, new ModuleType[] { ModuleType.COMMON_SWIPER }, timeout, TimeUnit.SECONDS);
			if (openedModuleTypes == null || openedModuleTypes.length <= 0) {
				HPLog.i(TAG, "start card reader,but return is none!may user canceled?");
				return null;
			}
			if (openedModuleTypes.length > 1) {
				HPLog.i(TAG, "should return only one type of card read action! but is " + openedModuleTypes.length);
				throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED, "should return only one type of card read action!but is " + openedModuleTypes.length);
			}
			switch (openedModuleTypes[0]) {
			case COMMON_SWIPER:
				Swiper swiper = (Swiper) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_SWIPER);
				SwipResult swipRslt = getSwipResult(swiper, MKIndexConst.DEFAULT_TRACK_WK_INDEX, MESeriesConst.TrackEncryptAlgorithm.BY_HANDPAY_MODEL, factor, dynamicData);
				if (swipRslt.getRsltType() == SwipResultType.SUCCESS) {
					return swipRslt;
				}
				throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED, "swipe failed:" + swipRslt.getRsltType());
				// case COMMON_SWIPER_ERROR:
				// throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED,
				// "swip failed: COMMON_SWIPER_ERROR");
			default:
				throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED, "not support card reader module:" + openedModuleTypes[0]);
			}
		} finally {
			cardReader.closeCardReader();
		}
	}

	private SwipResult getSwipResult(Swiper swiper, int trackKey, String encryptType, String factor, byte[] dynamicData) {
		SwipResult swipRslt = swiper.readSimposResult(new SwiperReadModel[] { SwiperReadModel.READ_SECOND_TRACK, SwiperReadModel.READ_THIRD_TRACK }, TrackSecurityPaddingType.STANDARD_MODEL, new WorkingKey(trackKey, CommonUtils.hexStringToBytes(factor)), encryptType, dynamicData, null);
		return swipRslt;
	}

	/**
	 * 获取随机数
	 * 
	 * @param length
	 * @return
	 */
	public static byte[] getRandom(int length) {
		if (length < 1) {
			return null;
		}
		Random random = new Random();
		byte[] bytes = new byte[length];
		random.nextBytes(bytes);
		return bytes;
	}

	public static byte[] getDynamicKeyData() {
		try {
			byte[] rand = getRandom(8);
			// FIX RANDOM
			// rand = CommonUtils.hexStringToBytes("08745B3041F93398");
			return rand;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public String encData(String data, String index, String factor) {
		String result = null;

		if (ISwiperListener.MacDataIndex.equals(index)) {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			try {
				bos.write(String.valueOf(data.toCharArray()).getBytes());
				bos.write(0x80);
				while (bos.size() % 8 != 0) {
					bos.write(0x00);
				}
				bos.write(0x80);
				for (int i = 0; i < 7; i++) {
					bos.write(0x00);
				}
				byte[] macPlainBytes = bos.toByteArray();
				HPLog.i(TAG, "mac :" + CommonUtils.bytesToHexString(macPlainBytes));
				result = encMac(macPlainBytes, factor);
			} catch (IOException ioe) {
				HPLog.e(TAG, "", ioe);
				try {
					bos.close();
				} catch (IOException e) {
					HPLog.e(TAG, "", e);
				}
			}

		} else if (ISwiperListener.KeyDataIndex.equals(index)) {
			if (mFlag == SwiperMode.NORMAL_TRANS) {
				result = encData(data, factor);
			} else {
				data = contentToEncry(data, index);
				result = encData(data, factor);
			}

		}
		// } else if (mFlag == SwiperMode.SUPER_TRANS) {
		// if (ISwiperListener.MacDataIndex.equals(index)) {
		// result = encMac(data.getBytes(), factor);
		// } else if (ISwiperListener.KeyDataIndex.equals(index)) {
		//
		// }
		// }
		return result;
	}

	@Override
	public Hashtable<String, String> batchEncData(Hashtable<Integer, String> htDatas, String factor) {
		return null;
	}

	private SwiperMode mFlag;

	@Override
	public boolean setMode(SwiperMode flag) {
		mFlag = flag;
		clearData();
		return true;
	}

	private void clearData() {
		mAmount = null;
	}

	private String mAmount = null;

	@Override
	public Result affirmAmount(String amount, int timeout) {
		mAmount = amount;
		return Result.OK;
	}

	PinInputEvent event = null;

	@Override
	public Result inputPwd(final String factor, final int timeout) {
		if (!connect()) {
			return Result.ERROR;
		}
		String accHashId = mHTData.get(BANK_ACCOUNT_HASH_KEY);
		String plainAcc = mHTData.get(BANK_PLAIN_ACCOUNT_KEY);
		String DCData = mHTData.get(BANK_DCDATA);
		String pin = mHTData.get(BANK_PAN_KEY);
		// 前面貌似没有刷卡，报错！
		if (TextUtils.isEmpty(DCData) && (TextUtils.isEmpty(accHashId) || TextUtils.isEmpty(plainAcc))) {
			HPLog.e(TAG, "no card relative info.");
			return Result.CANCEL;
		}
		final String msg;
		// 有输入金额：转账
		// 无输入金额：余额查询
		String inputPwd = mContext.getString(R.string.newland_input_pwd);
		if (!TextUtils.isEmpty(mAmount)) {
			BigDecimal bd = new BigDecimal(mAmount);
			bd = bd.divide(new BigDecimal("100"));
			msg = mContext.getString(R.string.newland_amount) + bd.toString() + "\n" + inputPwd;
		} else {
			msg = inputPwd;
		}
		// PinInputEvent event = null;
		// 如果没有获取到银行卡密码，进入银行卡密码输入界面
		if (TextUtils.isEmpty(pin)) {
			clearScreen();
			try {
				final PinInput pinInput = (PinInput) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_PININPUT);
				// IC卡输入密码
				if (!TextUtils.isEmpty(DCData)) {
					try {
						event = startPininput(AccountInputType.UNUSE_ACCOUNT, CommonUtils.str2Bcd(factor), "00000000000000000000", 6, true, msg, timeout);
					} catch (InterruptedException e) {
						HPLog.e("startPininput", e.toString());
					}
				}
				// 磁条卡输入密码
				else {
					event = pinInput.startStandardPinInput(new WorkingKey(MKIndexConst.DEFAULT_PIN_WK_INDEX, CommonUtils.hexStringToBytes(factor)), PinManageType.FIXED, AccountInputType.UNUSE_ACCOUNT, "00000000000000000000", 6, new byte[] { 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F' }, true, msg, timeout, TimeUnit.SECONDS);
				}

				clearScreen();
				// FIXME 如何处理超时问题的？
				if (event == null) {
					return Result.CANCEL;
				}
			} catch (ProcessTimeoutException processTimeoutException) {
				return Result.TIMEOUT;
			} catch (DeviceRTException dre) {
				return Result.ERROR;
			}
			pin = CommonUtils.bytesToHexString(event.getEncrypPin());
			if ("0000000000000000".equals(pin)) {
				pin = null;
			}
		}
		// 加密卡号。加密账号，需要先转化为hex。
		String encAcc = null;
		if (mFlag == SwiperMode.NORMAL_TRANS) {
			encAcc = encData(CommonUtils.string2Hex(plainAcc), ISwiperListener.KeyDataIndex, factor);
		} else if (mFlag == SwiperMode.SUPER_TRANS) {
			encAcc = encData(plainAcc, ISwiperListener.KeyDataIndex, factor);
			if (ClientEngine.getInstance().getGlobal(BANK_TransactionType_KEY) != null && ClientEngine.getInstance().getGlobal(BANK_TransactionType_KEY).equals("PurchaseAdvice")) {
				HPLog.e("fyang", "新增内容");
				HPLog.e("fyang", "加密之前merchantId" + ShowHtmlActivity.map.get("merchantId"));
				HPLog.e("fyang", "加密之前的orderId" + ShowHtmlActivity.map.get("orderId"));
				HPLog.e("fyang", "加密之前的terminalId" + ShowHtmlActivity.map.get("terminalId"));
				HPLog.e("fyang", ShowHtmlActivity.map.get("transAmount") + "加密之前的amount" + CommonUtils.formatMoneyToPos(ShowHtmlActivity.map.get("transAmount"), UPConfig.SUPER_TRANS_AMOUNT_LEN));
				String merchantId = encData(ShowHtmlActivity.map.get("merchantId"), ISwiperListener.KeyDataIndex, factor);
				String orderId = encData(ShowHtmlActivity.map.get("orderId"), ISwiperListener.KeyDataIndex, factor);
				String terminalId = encData(ShowHtmlActivity.map.get("terminalId"), ISwiperListener.KeyDataIndex, factor);
				String transAmount = encData(CommonUtils.formatMoenyToUnionpay(ShowHtmlActivity.map.get("transAmount")), ISwiperListener.KeyDataIndex, factor);
				HPLog.e("merchantId", merchantId);
				HPLog.e("orderId", orderId);
				HPLog.e("terminalId", terminalId);
				HPLog.e("transAmount", transAmount);
				// 先保存为全局变量,备用
				ClientEngine.getInstance().saveGlobal(BANK_MerchantID_KEY, merchantId);
				ClientEngine.getInstance().saveGlobal(BANK_OrderID_KEY, orderId);
				ClientEngine.getInstance().saveGlobal(BANK_TerminalID_KEY, terminalId);
				ClientEngine.getInstance().saveGlobal(BANK_TransAmount_KEY, transAmount);
				mHTData.put(BANK_MerchantID_KEY, merchantId);
				mHTData.put(BANK_OrderID_KEY, orderId);
				mHTData.put(BANK_TerminalID_KEY, terminalId);
				mHTData.put(BANK_TransAmount_KEY, transAmount);
			}
		}
		if (!TextUtils.isEmpty(pin) && !TextUtils.isEmpty(encAcc)) {
			mHTData.put(BANK_PAN_KEY, pin.toUpperCase(Locale.US));
			mHTData.put(BANK_ACCOUNT_KEY, encAcc);
			if (!TextUtils.isEmpty(mAmount)) {
				// 加密金额
				String encAmt = encData(mAmount, ISwiperListener.KeyDataIndex, factor);
				if (!TextUtils.isEmpty(encAmt)) {
					mHTData.put(BANK_AMOUNT_KEY, encAmt);
					return Result.OK;
				}
				HPLog.i(TAG, "enc amount error!");
				return Result.ERROR;
			} else {
				return Result.OK;
			}
		} else {
			HPLog.e(TAG, "encData error!");
			return Result.ERROR;
		}
	}

	@Override
	public SwipeResult registerPwd(String factor, int timeout) {
		if (!connect()) {
			return new SwipeResult(SwipeStatus.SWIPE_ERROR);
		}
		String inputPwd = mContext.getString(R.string.newland_input_pwd);
		String msg = inputPwd;
		PinInputEvent event;
		try {
			PinInput pinInput = (PinInput) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_PININPUT);
			clearScreen();
			// FIXME 和新大陆沟通该问题: 角落阳光: 可以,卡号可以全传0,解密密码时也用全0当账号解析.长度自定义
			event = pinInput.startStandardPinInput(new WorkingKey(MKIndexConst.DEFAULT_PIN_WK_INDEX, CommonUtils.hexStringToBytes(factor)), PinManageType.FIXED, AccountInputType.UNUSE_ACCOUNT, "00000000000000000000", 6, new byte[] { 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F' }, true, msg, timeout, TimeUnit.SECONDS);
			clearScreen();
			if (event == null) {
				return new SwipeResult(SwipeStatus.SWIPE_CANCEL);
			}
		} catch (ProcessTimeoutException processTimeoutException) {
			return new SwipeResult(SwipeStatus.SWIPE_TIMEOUT);
		}
		String pin = CommonUtils.bytesToHexString(event.getEncrypPin());
		return new SwipeResult(SwipeStatus.SWIPE_OK, pin);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Hashtable<String, String> getBankInfo() {
		Hashtable<String, String> result = (Hashtable<String, String>) mHTData.clone();
		mHTData.clear();
		return result;
	}

	@Override
	public boolean isSwiperReady() {
		return mIsSwiperOK;
	}

	@Override
	public SwiperModel getSwiperModel() {
		return SwiperModel.NEWLAND_BLUETOOTH;
	}

	/**
	 * 事件线程阻塞控制监听器.
	 * 
	 * @author lance
	 * 
	 * @param <T>
	 */
	private class EventHolder<T extends DeviceEvent> implements DeviceEventListener<T> {
		private T event;
		private final Object syncObj = new Object();
		private boolean isClosed = false;

		public void onEvent(T event, Handler handler) {
			this.event = event;
			synchronized (syncObj) {
				isClosed = true;
				syncObj.notify();
			}
		}

		public Handler getUIHandler() {
			return null;
		}

		void startWait() throws InterruptedException {
			synchronized (syncObj) {
				if (!isClosed)
					syncObj.wait();
			}
		}
	}

	public class AppExCode {

		public static final int DRIVER_NOT_FOUND = 1000;

		public static final int INIT_DRIVER_FAIED = 1001;

		public static final int INIT_DEVICE_PARAMS_FAILED = 1002;

		public static final int GET_TRACKTEXT_FAILED = 1003;

		public static final int GET_PININPUT_FAILED = 1004;

		public static final int GET_KEYBOARD_VALUE_FAILED = 1005;

		public static final int GET_PLAIN_ACCOUNT_NO_FAILED = 1006;

		public static final int MK_INDEX_NOTFOUND_ERROR = 1007;

		public static final int LOAD_WORKINGKEY_FAILED = 1009;
	}

	/**
	 * 主密钥索引
	 * <p>
	 * 
	 * 各索引若相同则表示使用同一组主密钥索引
	 * 
	 * @author lance
	 * 
	 */
	public static class MKIndexConst {

		/**
		 * 主密钥索引
		 */
		public static final int DEFAULT_MK_INDEX = 1;
		/**
		 * 默认PIN加密工作密钥索引
		 */
		public static final int DEFAULT_PIN_WK_INDEX = 2;
		/**
		 * 默认MAC加密工作密钥索引
		 */
		public static final int DEFAULT_MAC_WK_INDEX = 3;
		/**
		 * 默认磁道加密工作密钥索引
		 */
		public static final int DEFAULT_TRACK_WK_INDEX = 4;

		public static final int DEFAULT_MUTUALAUTH_WK_INDEX = 5;
	}

	/**
	 * 超级转账模式下模式下，数据的处理
	 * 
	 * @param data
	 * @param keyIndex
	 * @return
	 */
	private String contentToEncry(String data, String keyIndex) {
		data = StringToA(data);
		// 只有做mac的时候，需要补80
		if (ISwiperListener.MacDataIndex.equals(keyIndex)) {
			data = data + "80";
		}
		StringBuilder builder;
		if (data.length() % 16 != 0) {
			builder = new StringBuilder();
			builder.append(data);
			while (builder.toString().length() % 16 != 0) {
				builder.append("0");
			}
			data = builder.toString();
		}
		return data;
	}

	/**
	 * 将string转化为ascii
	 */
	private String StringToA(String content) {
		String result = "";
		int max = content.length();
		for (int i = 0; i < max; i++) {
			char c = content.charAt(i);
			String ss = Integer.toHexString((int) c);
			result = result + ss;
		}
		return result;
	}

	private String packageByte(String str) {
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			bos.write(str.getBytes().length);
			bos.write(str.getBytes());
			if (bos.size() % 8 != 0) {
				bos.write(0x80);
			}
			while (bos.size() % 8 != 0) {
				bos.write(0x00);
			}
			return new String(bos.toByteArray());
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		return null;
	}

	// //////////////////////////////////////////////////////
	// IC卡
	private ICTransferListener icTransferListener = new ICTransferListener();

	private void isConnected() {
		synchronized (ME3X_DRIVER_NAME) {
			if (null == mDeviceManager || mDeviceManager.getDevice() == null) {
				throw new DeviceOutofLineException("device not connect!");
			}
		}
	}

	private <T extends AbstractProcessDeviceEvent> T preEvent(T event, int defaultExCode) {
		if (!event.isSuccess()) {
			if (event.isUserCanceled()) {
				return null;
			}
			if (event.getException() != null) {
				if (event.getException() instanceof RuntimeException) {// 运行时异常直接抛出.
					throw (RuntimeException) event.getException();
				}
				throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED, "open card reader meet error!", event.getException());
			}
			throw new DeviceRTException(ExCode.UNKNOWN, "unknown exception!defaultExCode:" + defaultExCode);
		}
		return event;
	}

	/**
	 * 
	 * @param cardReaders
	 * @param msg
	 * @param amt
	 * @param factor
	 * @param dynamicKeyData
	 * @param timeout
	 * @param timeunit
	 * @param transferListener
	 * @return null 表示取消
	 */
	private SwipResult startTransfer(ModuleType[] cardReaders, String msg, BigDecimal amt, String factor, byte[] dynamicKeyData, long timeout, TimeUnit timeunit, TransferListener transferListener) {
		isConnected();
		CardReader cardReader = (CardReader) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_CARDREADER);
		if (cardReader == null) {
			throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED, "not support read card!");
		}
		try {
			EventHolder<OpenCardReaderEvent> listener = new EventHolder<OpenCardReaderEvent>();
			cardReader.openCardReader(msg, cardReaders, timeout, timeunit, listener);
			try {
				listener.startWait();
			} catch (InterruptedException e) {
				cardReader.cancelCardRead();
				return new SwipResult(SwipResultType.READTRACK_TIMEOUT);
			} finally {
				clearScreen();
			}
			OpenCardReaderEvent event = listener.event;
			// event.getException()
			if (!event.isSuccess()) {
				if (event.isUserCanceled()) {
					return null;
				} else if (null != event.getException() && event.getException() instanceof ProcessTimeoutException) {
					return new SwipResult(SwipResultType.READTRACK_TIMEOUT);
				} else if (event.isFailed() || null != event.getException()) {
					return new SwipResult(SwipResultType.SWIP_FAILED);
				}
				// TODO 暂时失败处理
				return new SwipResult(SwipResultType.SWIP_FAILED);
			}
			ModuleType[] openedModuleTypes = event.getOpenedCardReaders();
			if (openedModuleTypes == null || openedModuleTypes.length <= 0) {
				HPLog.e("startTransfer", "start cardreader,but return is none!may user canceled?");
				return null;
			}
			if (openedModuleTypes.length > 1) {
				HPLog.w("startTransfer", "should return only one type of cardread action!but is " + openedModuleTypes.length);
				throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED, "should return only one type of cardread action!but is " + openedModuleTypes.length);
			}
			switch (openedModuleTypes[0]) {
			case COMMON_SWIPER:
				int trackKey = MKIndexConst.DEFAULT_TRACK_WK_INDEX;
				Swiper swiper = (Swiper) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_SWIPER);
				SwipResult swipRslt = getSwipResult(swiper, trackKey, TrackEncryptAlgorithm.BY_HANDPAY_MODEL, factor, dynamicKeyData);
				HPLog.e("swipRslt.getRsltType()", swipRslt.getRsltType().name());
				HPLog.e("SwipResultType.SUCCESS", SwipResultType.SUCCESS.name());
				if (swipRslt.getRsltType() == SwipResultType.SUCCESS) {
					return swipRslt;
				}
				// TODO 刷卡失败
				return new SwipResult(SwipResultType.SWIP_FAILED);
			case COMMON_NCCARD:
				if (amt == null) {
					amt = new BigDecimal(0);
				} else {
					// amt = new BigDecimal(amt.doubleValue()/100);
				}
				QPBOCModule qPBOCModule = (QPBOCModule) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_QPBOC);
				EmvTransInfo emvTransInfo = qPBOCModule.startQPBOC(0x00, 0x0B, amt, timeout, timeunit, true);
				try {
					transferListener.onRequestOnline(null, emvTransInfo);
				} catch (Exception e) {
					e.printStackTrace();
				}
				// transferListener.onQpbocFinished(emvTransInfo);
				throw new DeviceRTException(Integer.MIN_VALUE, "IC");
			case COMMON_ICCARD:
				EmvModule module = (EmvModule) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_EMV);
				// OnlinePinConfig config = new OnlinePinConfig();
				// config.setWorkingKey(new WorkingKey(
				// MKIndexConst.DEFAULT_PIN_WK_INDEX,
				// CommonUtils.hexStringToBytes(factor)));
				// config.setPinManageType(PinManageType.FIXED);
				// config.setPinPadding(new byte[] { 'F', 'F', 'F', 'F', 'F',
				// 'F', 'F', 'F', 'F', 'F' });
				// config.setDisplayContent("请输入密码:");
				// config.setTimeout((int)timeout);
				// config.setInputMaxLen(6);
				// config.setEnterEnabled(true);
				// module.setOnlinePinConfig(config);
				// EmvTransController controller = module
				// .getEmvTransController(transferListener);
				// controller.startEmv(amt, new BigDecimal("0"), true);
				module.setOnlinePinConfig(null);
				EmvTransController controller = module.getEmvTransController(transferListener);
				controller.startEmv(0, 1, new BigDecimal("0"), true);
				icSwipeResult = null;
				lock();
				throw new DeviceRTException(Integer.MIN_VALUE, "IC");
			default: {
				throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED, "not support cardreader module:" + openedModuleTypes[0]);
			}
			}

		} finally {
			cardReader.closeCardReader();
		}
	}

	private void doICTransfer(final EmvTransInfo context, String factor) {
		try {
			// 1.拼DCData
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			HPLog.e("82", ISOUtils.hexString(context.getApplicationInterchangeProfile()));
			byte[] bytes82 = context.getApplicationInterchangeProfile();
			if (bytes82 != null) {
				bos.write((byte) 0x82);
				bos.write(bytes82.length);
				bos.write(bytes82);
			}
			HPLog.e("9F36", ISOUtils.hexString(context.getAppTransactionCounter()));
			byte[] bytes9F36 = context.getAppTransactionCounter();
			if (bytes9F36 != null) {
				bos.write((byte) 0x9F);
				bos.write((byte) 0x36);
				bos.write(bytes9F36.length);
				bos.write(bytes9F36);
			}
			HPLog.e("9F26", ISOUtils.hexString(context.getAppCryptogram()));
			byte[] bytes9F26 = context.getAppCryptogram();
			if (bytes9F26 != null) {
				bos.write((byte) 0x9F);
				bos.write((byte) 0x26);
				bos.write(bytes9F26.length);
				bos.write(bytes9F26);
			}
			HPLog.e("9F27", CommonUtils.bytesToHexString(new byte[] { context.getCryptogramInformationData() }));
			byte[] bytes9F27 = new byte[] { context.getCryptogramInformationData() };
			if (bytes9F27 != null) {
				bos.write((byte) 0x9F);
				bos.write((byte) 0x27);
				bos.write(bytes9F27.length);
				bos.write(bytes9F27);
			}
			HPLog.e("9F33", ISOUtils.hexString(context.getTerminal_capabilities()));
			byte[] bytes9F33 = context.getTerminal_capabilities();
			if (bytes9F33 != null) {
				bos.write((byte) 0x9F);
				bos.write((byte) 0x33);
				bos.write(bytes9F33.length);
				bos.write(bytes9F33);
			}
			HPLog.e("95", ISOUtils.hexString(context.getTerminalVerificationResults()));
			byte[] bytes95 = context.getTerminalVerificationResults();
			if (bytes95 != null) {
				bos.write((byte) 0x95);
				bos.write(bytes95.length);
				bos.write(bytes95);
			}
			HPLog.e("9F37", ISOUtils.hexString(context.getUnpredictableNumber()));
			byte[] bytes9F37 = context.getUnpredictableNumber();
			if (bytes9F37 != null) {
				bos.write((byte) 0x9F);
				bos.write((byte) 0x37);
				bos.write(bytes9F37.length);
				bos.write(bytes9F37);
			}
			HPLog.e("9F02", context.getAmountAuthorisedNumeric());
			String str9F02 = CommonUtils.formatMoneyToPos(context.getAmountAuthorisedNumeric(), 12);
			byte[] bytes9F02 = CommonUtils.str2Bcd(str9F02);
			if (bytes9F02 != null) {
				bos.write((byte) 0x9F);
				bos.write((byte) 0x02);
				bos.write(bytes9F02.length);
				bos.write(bytes9F02);
			}
			HPLog.e("9F03", context.getAmountOtherNumeric());
			String str9F03 = CommonUtils.formatMoneyToPos(context.getAmountOtherNumeric(), 12);
			byte[] bytes9F03 = CommonUtils.str2Bcd(str9F03);
			if (bytes9F03 != null) {
				bos.write((byte) 0x9F);
				bos.write((byte) 0x03);
				bos.write(bytes9F03.length);
				bos.write(bytes9F03);
			}
			HPLog.e("9F1A", context.getTerminalCountryCode());
			String str9F1A = context.getTerminalCountryCode();
			byte[] bytes9F1A = CommonUtils.str2Bcd(str9F1A);
			if (bytes9F1A != null) {
				bos.write((byte) 0x9F);
				bos.write((byte) 0x1A);
				bos.write(bytes9F1A.length);
				bos.write(bytes9F1A);
			}
			HPLog.e("5F2A", context.getTransactionCurrencyCode());
			String str5F2A = context.getTransactionCurrencyCode();
			byte[] bytes5F2A = CommonUtils.str2Bcd(str5F2A);
			if (bytes5F2A != null) {
				bos.write((byte) 0x5F);
				bos.write((byte) 0x2A);
				bos.write(bytes5F2A.length);
				bos.write(bytes5F2A);
			}
			HPLog.e("9A", context.getTransactionDate());
			String str9A = context.getTransactionDate();
			byte[] bytes9A = CommonUtils.str2Bcd(str9A);
			if (bytes9A != null) {
				bos.write((byte) 0x9A);
				bos.write(bytes9A.length);
				bos.write(bytes9A);
			}
			HPLog.e("9C", CommonUtils.bytesToHexString(new byte[] { context.getTransactionType().byteValue() }));
			byte[] bytes9C = new byte[] { context.getTransactionType().byteValue() };
			if (bytes9C != null) {
				bos.write((byte) 0x9C);
				bos.write(bytes9C.length);
				bos.write(bytes9C);
			}
			HPLog.e("9F10", ISOUtils.hexString(context.getIssuerApplicationData()));
			byte[] bytes9F10 = context.getIssuerApplicationData();
			if (bytes9F10 != null) {
				bos.write((byte) 0x9F);
				bos.write((byte) 0x10);
				bos.write(bytes9F10.length);
				bos.write(bytes9F10);
			}
			byte[] dcDatas = bos.toByteArray();
			bos.close();
			String dcdata = CommonUtils.bytesToHexString(dcDatas);
			String icnumber = context.getCardSequenceNumber();
			if (!TextUtils.isEmpty(icnumber)) {
				while (icnumber.length() < 3) {
					icnumber = "0" + icnumber;
				}
				mHTData.put(BANK_ICNUMBER, icnumber);
			}
			String account = context.getCardNo();
			byte[] encPin = context.getOnLinePin();
			SwipResult swipResult = getTrackText(factor, ISOUtils.hex2byte(mDynamicKey));
			if (null != swipResult.getSecondTrackData()) {
				String track2 = CommonUtils.bytesToHexString(swipResult.getSecondTrackData());
				HPLog.i(HPLog.FDL_TAG, "TRACK2_KEY = " + track2);
				mHTData.put(BANK_TRACK2_KEY, track2.toUpperCase(Locale.US));
			}
			mHTData.put(BANK_DCDATA, dcdata.toUpperCase(Locale.US));
			mHTData.put(BANK_PLAIN_ACCOUNT_KEY, account);

			// 新版2.0.0 expiryDate
			String expireDate = context.getCardExpirationDate();
			HPLog.i(HPLog.FDL_TAG, TAG + "  -- plainExpireDate:" + expireDate);
			if (CommonUtils.checkExpireDate(expireDate)) {
				expireDate = expireDate.substring(0, 4);
				HPLog.i(HPLog.FDL_TAG, TAG + "  -- plainExpireDate:" + expireDate);
				mHTData.put(IBusinessSwiper.BANK_PLAIN_EXPIRE_DATE, expireDate);
			} else {
				String track2 = CommonUtils.bytesToHexString(context.getTrack_2_eqv_data());
				HPLog.i(HPLog.FDL_TAG, "TRACK2_KEY = " + track2);
				if (!TextUtils.isEmpty(track2) && track2.contains("d")) {
					try {
						int dIndex = track2.indexOf("d") + 1;
						expireDate = track2.substring(dIndex, dIndex + 4);
						HPLog.i(HPLog.FDL_TAG, "TRACK2_KEY = " + expireDate);
						mHTData.put(IBusinessSwiper.BANK_PLAIN_EXPIRE_DATE, expireDate);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				HPLog.i(TAG, TAG + " IC card but no plainExpireDate");
			}

			boolean isNeedPwd = true;
			// 用户直接输入确认，下面会返回8个字节的全零。我们需要把他当每输入密码
			if (encPin != null && "0000000000000000".equals(CommonUtils.bytesToHexString(encPin))) {
				encPin = null;
			}
			if (encPin != null) {
				mHTData.put(BANK_PAN_KEY, CommonUtils.bytesToHexString(encPin));
				isNeedPwd = false;
			}
			icSwipeResult = new SwipeResult(SwipeStatus.SWIPE_OK, account, isNeedPwd);
		} catch (IOException e) {
			HPLog.e("doICTransfer", e.toString());
		}
	}

	public SwipResult getTrackText(String factor, byte[] dynamicKeyData) {
		Swiper swiper = (Swiper) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_SWIPER);
		SwipResult swipRslt = swiper.readEncryptResult(new SwiperReadModel[] { SwiperReadModel.READ_IC_SECOND_TRACK }, TrackSecurityPaddingType.STANDARD_MODEL, new WorkingKey(MKIndexConst.DEFAULT_TRACK_WK_INDEX, CommonUtils.hexStringToBytes(factor)), TrackEncryptAlgorithm.BY_HANDPAY_MODEL, dynamicKeyData, null);
		if (swipRslt.getRsltType() == SwipResultType.SUCCESS) {
			return swipRslt;
		}
		throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED, "swip failed:" + swipRslt.getRsltType());
	}

	private interface TransferListener extends EmvControllerListener {

		void onOpenCardreaderCanceled();
	}

	private class ICTransferListener implements TransferListener {
		private String mFactor;

		public void setFactor(String factor) {
			mFactor = factor;
		}

		@Override
		public void onEmvFinished(boolean arg0, EmvTransInfo context) throws Exception {
			// doICTransfer(context);
			// 在插入IC卡，输入密码的时候，拔掉刷卡器，会直接进入这个回调。所以我们需要unlock。
			unlock();
			HPLog.i("NewlandSwiperBT", "onEmvFinished");
		}

		@Override
		public void onError(EmvTransController arg0, Exception arg1) {
			HPLog.i("NewlandSwiperBT", "onError", arg1);
			unlock();
			arg0.cancelEmv();
		}

		@Override
		public void onFallback(EmvTransInfo arg0) throws Exception {
			// 应该降级交易，我们就当失败了。
			HPLog.i("NewlandSwiperBT", "onFallback");
			unlock();
		}

		@Override
		public void onRequestOnline(EmvTransController controller, EmvTransInfo context) throws Exception {
			HPLog.i("NewlandSwiperBT", "onRequestOnline");
			doICTransfer(context, mFactor);
			unlock();
		}

		@Override
		public void onRequestPinEntry(EmvTransController arg0, EmvTransInfo arg1) throws Exception {
			HPLog.i("NewlandSwiperBT", "onRequestPinEntry");
			unlock();
			arg0.cancelEmv();
		}

		@Override
		public void onRequestSelectApplication(EmvTransController arg0, EmvTransInfo arg1) throws Exception {
			HPLog.i("NewlandSwiperBT", "onRequestSelectApplication");
			unlock();
			arg0.cancelEmv();
		}

		@Override
		public void onRequestTransferConfirm(EmvTransController arg0, EmvTransInfo arg1) throws Exception {
			HPLog.i("NewlandSwiperBT", "onRequestTransferConfirm");
			unlock();
			arg0.cancelEmv();
		}

		@Override
		public void onOpenCardreaderCanceled() {
		}

	}

	// /**
	// * 磁条卡交易
	// */
	// private SwipResult startSwipTransfer(final SwipResult sr, final String
	// message, final String amt, final long timeout, final TimeUnit timeUnit,
	// final String factor)
	// {
	// CardReader cardReader = (CardReader) mDeviceManager.getDevice()
	// .getStandardModule(ModuleType.COMMON_CARDREADER);
	// if (cardReader == null)
	// {
	// throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED,
	// "not support read card!");
	// }
	// try
	// {
	// EventHolder<OpenCardReaderEvent> listener = new
	// EventHolder<OpenCardReaderEvent>();
	// cardReader.openCardReader(message,
	// new ModuleType[] { ModuleType.COMMON_SWIPER }, timeout,
	// timeUnit, listener);
	// try
	// {
	// listener.startWait();
	// }
	// catch (InterruptedException e)
	// {
	// cardReader.cancelCardRead();
	// transferListener.onOpenCardreaderCanceled();
	// }
	// finally
	// {
	// clearScreen();
	// }
	// OpenCardReaderEvent event = listener.event;
	// event = preEvent(event, AppExCode.GET_TRACKTEXT_FAILED);
	// if (event == null)
	// {
	// return null;
	// }
	// ModuleType[] openedModuleTypes = event.getOpenedCardReaders();
	// if (openedModuleTypes == null || openedModuleTypes.length <= 0)
	// {
	// HPLog.e("startSwipTransfer","start cardreader,but return is none!may user canceled?");
	// return null;
	// }
	// if (openedModuleTypes.length > 1)
	// {
	// HPLog.e("startSwipTransfer","should return only one type of cardread action!but is "
	// + openedModuleTypes.length);
	// throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED,
	// "should return only one type of cardread action!but is "
	// + openedModuleTypes.length);
	// }
	// switch (openedModuleTypes[0])
	// {
	// case COMMON_SWIPER:
	// int trackKey = MKIndexConst.DEFAULT_TRACK_WK_INDEX;
	// Swiper swiper = (Swiper) mDeviceManager.getDevice()
	// .getStandardModule(ModuleType.COMMON_SWIPER);
	// SwipResult swipRslt = getSwipResult(swiper, trackKey,
	// TrackEncryptAlgorithm.BY_HANDPAY_MODEL, factor,
	// CommonUtils.hexStringToBytes(mDynamicKey));
	// if (swipRslt.getRsltType() == SwipResultType.SUCCESS)
	// {
	// return swipRslt;
	// }
	// throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED,
	// "swip failed:" + swipRslt.getRsltType());
	// default:
	// {
	// throw new DeviceRTException(AppExCode.GET_TRACKTEXT_FAILED,
	// "not support cardreader module:"
	// + openedModuleTypes[0]);
	// }
	// }
	// }
	// finally
	// {
	// cardReader.closeCardReader();
	// }
	// }

	public PinInputEvent startPininput(AccountInputType acctInputType, byte[] processKey, String acctHash, int inputMaxLen, boolean isEnterEnabled, String msg, long timeout) throws InterruptedException {
		isConnected();
		PinInput pinInput = (PinInput) mDeviceManager.getDevice().getStandardModule(ModuleType.COMMON_PININPUT);
		EventHolder<PinInputEvent> listener = new EventHolder<PinInputEvent>();
		pinInput.startStandardPinInput(new WorkingKey(MKIndexConst.DEFAULT_PIN_WK_INDEX, processKey), PinManageType.FIXED, acctInputType, acctHash, inputMaxLen, new byte[] { 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F' }, isEnterEnabled, msg, (int) timeout, TimeUnit.SECONDS, listener);
		try {
			listener.startWait();
		} catch (InterruptedException e) {
			pinInput.cancelPinInput();
			throw e;
		} finally {
			clearScreen();
		}
		PinInputEvent event = listener.event;
		event = preEvent(event, AppExCode.GET_PININPUT_FAILED);
		if (event == null) {
			return null;
		}
		return event;
	}

	private String message;

	private SwipeResult icSwipeResult;
	private static Object objLockBT = new Object();

	public static void lock() {
		synchronized (objLockBT) {
			try {
				HPLog.e("lock", "lock");
				objLockBT.wait();
			} catch (InterruptedException e) {
				HPLog.e("unlock", e.toString());
			}
		}
	}

	public static void unlock() {
		synchronized (objLockBT) {
			HPLog.e("unlock", "unlock");
			objLockBT.notify();
		}
	}

	@Override
	public void setPlainPwd(String pwd) {
		return;
	}

	@Override
	public boolean printBitMap(int position, Bitmap bitmap) {
		return false;
	}

	@Override
	public boolean printString(String data) {
		return false;
	}

	@Override
	public boolean print(String data, Bitmap bitmap) {
		return false;
	}

}
